<template>
  <div class="condition-tree__wrapper">
    <div v-if="(condition.conditions || []).length > 1" class="condition-tree__logical-part">
      <div class="condition-tree__line"></div>
      <el-select class="condition-tree__select" v-model="condition.logical" size="small">
        <el-option :label="t('conditionTree.logicalPart.and')" :value="LogicalOperator.And" />
        <el-option :label="t('conditionTree.logicalPart.or')" :value="LogicalOperator.Or" />
      </el-select>
    </div>
    <div class="condition-tree__condition-list">
      <div
        v-for="(item, conditionIndex) in condition.conditions"
        :key="`condition_item_${conditionIndex}`"
        class="condition-tree__condition-item"
      >
        <template v-if="'type' in item">
          <el-select v-model="item.field" filterable style="width: 150px">
            <template v-for="(schema, schemaIndex) in props.schemata">
              <template v-if="'options' in schema">
                <el-option-group :key="`schema_${schemaIndex}`" :label="schema.label">
                  <el-option
                    v-for="groupItem in schema.options"
                    :key="groupItem.field"
                    :label="groupItem.label"
                    :value="groupItem.field"
                  />
                </el-option-group>
              </template>

              <template v-else>
                <el-option
                  :key="`schema_${schemaIndex}`"
                  :label="schema.label"
                  :value="schema.field ?? ''"
                />
              </template>
            </template>
          </el-select>
          <el-select v-model="item.operator" style="width: 100px" @change="operatorChange(item)">
            <el-option
              v-for="(operator, operatorIndex) in conditionOperators"
              :key="`operator_${operatorIndex}`"
              :label="operator.label"
              :value="operator.value"
            />
          </el-select>
          <el-input
            v-show="item.type === ConditionExpressionType.Binary"
            v-model="item.value"
            style="width: 180px"
            :placeholder="t('conditionTree.conditionPart.value.placeholder')"
          />
          <!-- 添加/删除按钮 -->
          <el-dropdown trigger="click" @command="handleCommand">
            <el-button type="primary" link style="margin-left: 6px">
              <el-icon><Plus /></el-icon>
            </el-button>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item :command="{ type: 'new' }">{{
                  t('conditionTree.conditionPart.addNew')
                }}</el-dropdown-item>
                <el-dropdown-item :command="{ type: 'sub', id: item.id }">{{
                  t('conditionTree.conditionPart.addNewSub')
                }}</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>

          <el-button
            type="danger"
            link
            style="margin-left: 0"
            @click="deleteCondition(conditionIndex)"
          >
            <el-icon><Delete /></el-icon>
          </el-button>
        </template>
        <template v-else>
          <ConditionGroup :id="item.id" :schemata="schemata" />
        </template>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  ComparisonOperator,
  ConditionExpression,
  ConditionExpressionGroup,
  ConditionExpressionType,
  ConditionSchema,
  LogicalOperator
} from '@/components/ConditionTree/type'
import { useI18n } from 'vue-i18n'
import { conditionKey } from '@/components/ConditionTree/injectKey'
import { generateUUID } from '@/utils'
import { Delete, Plus } from '@element-plus/icons-vue'
import { PropType, UnwrapRef } from 'vue'

defineOptions({ name: 'ConditionGroup' })

// 定义 props
const props = defineProps({
  id: {
    type: String,
    required: true
  },
  schemata: {
    type: Array as PropType<ConditionSchema[]>,
    required: true
  }
})

const message = useMessage()

const { t } = useI18n()

// 注入整棵树
const allCondition =
  inject<
    Ref<
      UnwrapRef<ConditionExpressionGroup>,
      UnwrapRef<ConditionExpressionGroup> | ConditionExpressionGroup
    >
  >(conditionKey)

// 找到当前组件使用的条件节点
const findConditionNodeById = (node: ConditionExpressionGroup): ConditionExpressionGroup => {
  // 如果当前节点的ID匹配 则返回该节点
  if (node.id === props.id) {
    return node
  }

  // 如果当前节点不是叶子节点 递归查找子节点
  for (const child of node.conditions ?? []) {
    const result = findConditionNodeById(child as ConditionExpressionGroup)
    if (result) {
      return result // 找到目标节点，返回结果
    }
  }
}
const condition = findConditionNodeById(allCondition!.value)

const conditionOperators = [
  {
    value: ComparisonOperator.Equal,
    label: t('conditionTree.conditionPart.operators.equal')
  },
  {
    value: ComparisonOperator.NotEqual,
    label: t('conditionTree.conditionPart.operators.notEqual')
  },
  {
    value: ComparisonOperator.LessThan,
    label: t('conditionTree.conditionPart.operators.lessThan')
  },
  {
    value: ComparisonOperator.LessThanOrEqual,
    label: t('conditionTree.conditionPart.operators.lessThanOrEqual')
  },
  {
    value: ComparisonOperator.GreaterThan,
    label: t('conditionTree.conditionPart.operators.greaterThan')
  },
  {
    value: ComparisonOperator.GreaterThanOrEqual,
    label: t('conditionTree.conditionPart.operators.greaterThanOrEqual')
  },
  {
    value: ComparisonOperator.Like,
    label: t('conditionTree.conditionPart.operators.include')
  },
  {
    value: ComparisonOperator.NotLike,
    label: t('conditionTree.conditionPart.operators.exclude')
  },
  {
    value: ComparisonOperator.IsNull,
    label: t('conditionTree.conditionPart.operators.isEmpty')
  },
  {
    value: ComparisonOperator.IsNotNull,
    label: t('conditionTree.conditionPart.operators.isNotEmpty')
  }
]

// 产生一个空条件
const generateSimpleNode = (): ConditionExpression => {
  return {
    '@type': 'cn.cas.imr.postgraduate.framework.common.pojo.advanced.ConditionExpression',
    id: generateUUID(),
    type: ConditionExpressionType.Binary,
    field: '',
    operator: ComparisonOperator.Equal,
    value: ''
  }
}

// 添加新的条件
const addNewCondition = () => {
  condition.conditions.push(generateSimpleNode())
}

const addNewSubCondition = (id: string) => {
  if (condition.conditions.length === 1) {
    message.warning(t('conditionTree.conditionPart.addSubConditionWarning'))
    addNewCondition()
    return
  }
  // 将当前点击的节点 进化成一个组合条件
  const currentCondition = condition.conditions.find((item) => item.id === id)
  if (currentCondition) {
    // 从当前节点中移除当前节点
    const index = condition.conditions.indexOf(currentCondition)
    condition.conditions.splice(index, 1)
    // 进化出一个新的组合节点
    const newCondition: ConditionExpressionGroup = {
      '@type': 'cn.cas.imr.postgraduate.framework.common.pojo.advanced.ConditionExpressionGroup',
      id: generateUUID(),
      logical: LogicalOperator.And,
      conditions: [currentCondition, generateSimpleNode()]
    }
    // 在index的位置插入新的组合节点
    condition.conditions.splice(index, 0, newCondition)
  }
}

const handleCommand = (command: { type: string; id?: string }) => {
  if (command.type === 'new') {
    addNewCondition()
  } else if (command.type === 'sub' && command.id) {
    addNewSubCondition(command.id)
  }
}

const deleteCondition = (index: number) => {
  condition.conditions.splice(index, 1)
  // 判断外层是否是root节点
  if (condition.id === 'root') {
    // 外层是根节点了 不能再退化了
    return
  }

  // 判断剩余数量 如果只剩下一个条件 则退化节点
  if ('logical' in condition && condition.conditions.length === 1) {
    const lastCondition = condition.conditions[0]
    // 清空condition中的所有属性
    Object.keys(condition).forEach((key) => delete condition[key])
    // 将最后一个条件退化
    Object.assign(condition, lastCondition)
  }
}

const operatorChange = (item: ConditionExpression) => {
  // 明确指定数组的类型
  const nullCheckOperators: ComparisonOperator[] = [
    ComparisonOperator.IsNull,
    ComparisonOperator.IsNotNull
  ]
  // 判断是否是二元操作符
  const isBinary = !nullCheckOperators.includes(item.operator)
  item.type = isBinary ? ConditionExpressionType.Binary : ConditionExpressionType.Unary
  if (!isBinary) {
    item.value = ''
  }
}

defineExpose({
  addNewCondition
})
</script>

<style scoped lang="scss">
.condition-tree__wrapper {
  --line-color: var(--el-color-primary);

  box-sizing: border-box;
  display: flex;

  .condition-tree__logical-part {
    width: 70px;
    display: flex;
    padding: 10px 18px 10px 20px;
    position: relative;

    .condition-tree__line {
      width: 50px;
      border-top: 1px solid var(--line-color);
      border-left: 1px solid var(--line-color);
      border-bottom: 1px solid var(--line-color);
      border-radius: 10px 0 0 10px;
      position: relative;

      &:before {
        content: '';
        width: 10px;
        height: 10px;
        border: 1px solid var(--line-color);
        border-radius: 10px;
        position: absolute;
        top: -5px;
        right: -10px;
      }

      &:after {
        content: '';
        width: 10px;
        height: 10px;
        border: 1px solid var(--line-color);
        border-radius: 10px;
        position: absolute;
        bottom: -5px;
        right: -10px;
      }
    }

    :deep(.condition-tree__select) {
      position: absolute;
      width: 60px !important;
      top: 50%;
      left: 0;
      transform: translateY(-50%);
      background: var(--el-bg-color);

      .el-select__placeholder {
        text-align: center;
      }
    }
  }

  .condition-tree__condition-list {
    display: flex;
    flex-direction: column;
    gap: 5px;

    .condition-tree__condition-item {
      display: flex;
      gap: 5px;

      :deep(.el-select) {
        width: 140px;
      }

      :deep(.el-input) {
        //margin-left: 20px;
      }
    }
  }
}
</style>
